package com.hellohoper.script.config.engine.zookeeper;

import com.hellohoper.assembly.common.utils.util.JsonUtils;
import com.hellohoper.script.config.admin.app.dao.pojo.ScriptConfig;
import com.hellohoper.script.config.api.feign.ScriptConfigFeign;
import com.hellohoper.script.config.engine.container.ScriptContainer;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

/**
 * 脚本ZK监听
 * Created by hk on 17/8/21.
 */
@Configuration
public class ZookeeperListener implements InitializingBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCacheListener.class);

    @Autowired
    private CuratorFramework curatorFramework;

    @Autowired
    private Environment environment;

    @Autowired
    private ScriptConfigFeign scriptConfigFeign;

    @Autowired
    private ScriptContainer scriptContainer;

    /**
     * 监听脚本变化
     *
     * @throws Exception E
     */
    public void Listener() throws Exception {
        // path
        String path = "/" + environment.getProperty("spring.application.name");
        // 判断节点是否存
        Stat stat = curatorFramework.checkExists().forPath(path);
        // 持久节点不存在，创建节点`
        if (stat == null) {
            curatorFramework.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path);
        }
        //设置节点的cache
        TreeCache treeCache = new TreeCache(curatorFramework, path);
        //设置监听器和处理过程
        treeCache.getListenable().addListener(new ConfigCacheListener(path, scriptConfigFeign, scriptContainer));
        //开始监听
        treeCache.start();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Listener();
    }

    @Getter
    @Setter
    public static class ConfigCacheListener implements TreeCacheListener {
        private String path;
        private ScriptConfigFeign scriptConfigFeign;
        private ScriptContainer scriptContainer;

        public ConfigCacheListener(String path, ScriptConfigFeign scriptConfigFeign, ScriptContainer scriptContainer) {
            this.path = path;
            this.scriptConfigFeign = scriptConfigFeign;
            this.scriptContainer = scriptContainer;
        }

        @Override
        public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent event) throws Exception {
            ChildData data = event.getData();
            if (data == null) {
                LOGGER.error("Zookeeper Listener Data Is Null");
                return;
            }
            // ZK事件
            switch (event.getType()) {
                case NODE_ADDED:
                    addScript(scriptConfigFeign, new String(data.getData()));
                    LOGGER.info("NODE_ADDED : " + data.getPath() + "  数据:" + new String(data.getData()));
                    break;
                case NODE_REMOVED:
                    removeScript(scriptConfigFeign, new String(data.getData()));
                    LOGGER.info("NODE_REMOVED : " + data.getPath() + "  数据:" + new String(data.getData()));
                    break;
                case NODE_UPDATED:
                    addScript(scriptConfigFeign, new String(data.getData()));
                    LOGGER.info("NODE_UPDATED : " + data.getPath() + "  数据:" + new String(data.getData()));
                    break;
                default:
                    break;
            }

        }

        public void addScript(ScriptConfigFeign scriptConfigFeign, String data) {
            ScriptConfig scriptConfig = null;
            // 获得appName
            if (StringUtils.isNotEmpty(data)) {
                scriptConfig = JsonUtils.toObject(data, ScriptConfig.class);
            }
            if (scriptConfig == null) {
                return;
            }
            ScriptConfig scriptConfigDB = scriptConfigFeign.searchConfig(scriptConfig.getAppName(), scriptConfig.getScriptName());
            if (scriptConfigDB != null) {
                scriptContainer.addScript(scriptConfig.getAppName(),
                        scriptConfig.getScriptName(), scriptConfig.getScriptContent());
            }
        }

        public void removeScript(ScriptConfigFeign scriptConfigFeign, String data) {
            ScriptConfig scriptConfig = null;
            // 获得appName
            if (StringUtils.isNotEmpty(data)) {
                scriptConfig = JsonUtils.toObject(data, ScriptConfig.class);
            }
            if (scriptConfig == null) {
                return;
            }
            ScriptConfig scriptConfigDB = scriptConfigFeign.searchConfig(scriptConfig.getAppName(), scriptConfig.getScriptName());
            if (scriptConfigDB != null) {
                scriptContainer.removeScript(scriptConfig.getAppName(), scriptConfig.getScriptName());
            }
        }
    }
}
